using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Common;
using System.Globalization;
using System.Collections;
using System.Text;
using System.Data;
using System.Web.Configuration;
using ResourceBlender.DAL;
using ResourceBlender.Core;

/// <summary>
/// A page for managing applications
/// </summary>
public partial class Applications : LocalPage
{
    /// <summary>
    /// Disables gridlines if there are no applications
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void Page_Load(object sender, EventArgs e)
    {
        if(!Page.IsPostBack) {
            mltMain.ActiveViewIndex = 0;
            BindApplicationsGrid();
        }
        lblAddCustomLanguageError.Visible = false;
        lblAppExists.Visible = false;
    }

    /// <summary>
    /// Process edit/delete commands from the GridView
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewCommandEventArgs"/> instance containing the event data.</param>
    protected void grdApplications_RowCommand(object sender, GridViewCommandEventArgs e) {
        try {
            string applicationId = e.CommandArgument.ToString();
            RBApplication app = ResourceBlenderDAL.GetApplication(applicationId, true);
            switch(e.CommandName) {
                case "doedit":
                    mltMain.ActiveViewIndex = 1;
                    txtAppName.Text = app.ApplicationName;
                    txtDisplayName.Text = app.DisplayName;
                    string pTitle = I18nUtils.GetString("UIStrings", "EditingName", Server.HtmlEncode(txtDisplayName.Text));
                    Page.Title = pTitle + " &raquo; ResourceBlender.NET";
                    lblEditApplications.Text = pTitle;
                    litNavAddAddApplication.Text = I18nUtils.GetString("UIStrings", "EditApplication");
                    mltBundles.ActiveViewIndex = 0;
                    bundleEditor.ApplicationID = app.ID;
                    BindComboOptions(app.Languages.ToArray(), app.DefaultLanguage);
                    Session["appid"] = app.ID;
                    Session["editing"] = bool.TrueString;
                    break;
                case "confirmdelete":
                    mltMain.ActiveViewIndex = 2;
                    lblConfirmDelete.Text = I18nUtils.GetString("UIStrings", "DeleteAppPromptName", string.Format("<em>{0} ({1})</em>", app.ApplicationName, app.DisplayName));
                    Session["appid"] = applicationId;
                    break;
                default:
                    mltMain.ActiveViewIndex = 0;
                    break;
            }
        } catch(Exception ex) {
            lblErrorDescription.Text = ex.Message;
            mltMain.ActiveViewIndex = 3;
        }
    }

    /// <summary>
    /// Binds the applications GridView and removes gridlines if necessary.
    /// </summary>
    private void BindApplicationsGrid() {
        grdApplications.DataBind();
        if(grdApplications.Rows.Count == 0) {
            grdApplications.GridLines = GridLines.None;
        } else {
            grdApplications.GridLines = GridLines.Both;
        }
    }

    #region Adding/Editing
    /// <summary>
    /// Populates the 'Bundles' and language combo boxes
    /// </summary>
    /// <param name="selectedLanguages">The languages included in the application.</param>
    /// <param name="defaultLanguage">The default language.</param>
    private void BindComboOptions(string[] selectedLanguages, string defaultLanguage) {
        CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
        List<ListItem> availableCultures = new List<ListItem>(),
                       selectedCultures = new List<ListItem>(),
                       bundleList = new List<ListItem>();
        foreach(string selectedCode in selectedLanguages) {
            selectedCultures.Add(new ListItem(Utils.GetSafeEnglishName(selectedCode), selectedCode));
        }
        foreach(CultureInfo culture in cultures) {
            if(culture.Name.Length > 0) {
                if(!selectedLanguages.Contains(culture.Name)) {
                    availableCultures.Add(new ListItem(culture.EnglishName, culture.Name));
                }
            }
        }
        ListComparer comp = new ListComparer();
        availableCultures.Sort(comp);
        selectedCultures.Sort(comp);
        lstAvailableLangs.Items.Clear();
        lstSelectedLangs.Items.Clear();
        cboDefaultLanguage.Items.Clear();
        lstAvailableLangs.Items.AddRange(availableCultures.ToArray());
        lstSelectedLangs.Items.AddRange(selectedCultures.ToArray());
        cboDefaultLanguage.Items.AddRange(selectedCultures.ToArray());
        cboDefaultLanguage.SelectedValue = defaultLanguage;
        BindApplicationsGrid();
    }

    /// <summary>
    /// Shows a form to add a new application.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void lnkAddApplication_Click(object sender, EventArgs e) {
        mltMain.ActiveViewIndex = 1;
        Page.Title = I18nUtils.GetString("UIStrings", "AddApplication" + " &raquo; ResourceBlender.NET");
        txtAppName.Text = "";
        txtDisplayName.Text = "";
        mltBundles.ActiveViewIndex = 1;
        BindComboOptions(new string[] { }, "");
        cboDefaultLanguage.SelectedIndex = -1;
        lstAvailableLangs.SelectedIndex = -1;
        lstSelectedLangs.SelectedIndex = -1;
        Session["editing"] = bool.FalseString;
    }

    /// <summary>
    /// Adds a custom language or selects the code entered from the available list if it is not a custom language.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnAddCustomLanguage_Click(object sender, EventArgs e) {
        string code = txtCustomCode.Text;
        if(string.IsNullOrEmpty(code)) {
            return;
        }
        List<ListItem> newItems = new List<ListItem>(lstSelectedLangs.Items.Count+1);
        foreach(ListItem currentLanguage in lstSelectedLangs.Items) {
            if(currentLanguage.Value == code) {
                lblAddCustomLanguageError.Text = I18nUtils.GetString("Errors", "LanguageAlreadyAdded");
                lblAddCustomLanguageError.Visible = true;
                return;
            }
            newItems.Add(currentLanguage);
        }
        newItems.Add(new ListItem(code));
        newItems.Sort(new ListComparer());
        lstSelectedLangs.Items.Clear();
        ListItem[] newSelectedLangs = newItems.ToArray();
        lstSelectedLangs.Items.AddRange(newSelectedLangs);
        string currentDefaultLang = cboDefaultLanguage.SelectedValue;
        cboDefaultLanguage.Items.Clear();
        cboDefaultLanguage.Items.AddRange(newSelectedLangs);
        if(currentDefaultLang != null && currentDefaultLang.Length > 0) {
            cboDefaultLanguage.SelectedValue = currentDefaultLang;
        }
    }

    /// <summary>
    /// Validates one or more languages are selected.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="args">The <see cref="System.Web.UI.WebControls.ServerValidateEventArgs"/> instance containing the event data.</param>
    protected void validateHasLanguages(object source, ServerValidateEventArgs args) {
        args.IsValid = lstSelectedLangs.Items.Count > 0;
    }

    /// <summary>
    /// Moves a language from 'Selected languages' to 'Available languages'
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnRemoveLang_Click(object sender, EventArgs e) {
        if(lstSelectedLangs.SelectedItem == null) {
            return;
        }
        List<ListItem> newItems = new List<ListItem>(lstAvailableLangs.Items.Count+1);
        foreach(ListItem availableLanguage in lstAvailableLangs.Items) {
            newItems.Add(availableLanguage);
        }
        ListItem selectedLanguage;
        for(int i = lstSelectedLangs.Items.Count - 1; i >= 0; i--) {
            selectedLanguage = lstSelectedLangs.Items[i];
            if(selectedLanguage.Selected) {
                lstSelectedLangs.Items.Remove(selectedLanguage);
                cboDefaultLanguage.Items.Remove(selectedLanguage);
                selectedLanguage.Selected = false;
                newItems.Add(selectedLanguage);
            }
        }
        newItems.Sort(new ListComparer());
        lstAvailableLangs.Items.Clear();
        ListItem[] newAvailableLangs = newItems.ToArray();
        lstAvailableLangs.Items.AddRange(newAvailableLangs);
    }

    /// <summary>
    /// Moves a language from 'Available languages' to 'Selected languages'
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnAddLang_Click(object sender, EventArgs e) {
        if(lstAvailableLangs.SelectedItem == null) {
            return;
        }
        List<ListItem> newItems = new List<ListItem>(lstSelectedLangs.Items.Count+1);
        foreach(ListItem currentLanguage in lstSelectedLangs.Items) {
            newItems.Add(currentLanguage);
        }
        ListItem availableLanguage;
        for(int i=lstAvailableLangs.Items.Count-1;i>=0;i--) {
            availableLanguage = lstAvailableLangs.Items[i];
            if(availableLanguage.Selected) {
                lstAvailableLangs.Items.Remove(availableLanguage);
                availableLanguage.Selected = false;
                newItems.Add(availableLanguage);
            }
        }
        newItems.Sort(new ListComparer());
        lstSelectedLangs.Items.Clear();
        ListItem[] newSelectedLangs = newItems.ToArray();
        lstSelectedLangs.Items.AddRange(newSelectedLangs);
        string currentDefaultLang = cboDefaultLanguage.SelectedValue;
        cboDefaultLanguage.Items.Clear();
        cboDefaultLanguage.Items.AddRange(newSelectedLangs);
        if(currentDefaultLang != null && currentDefaultLang.Length > 0) {
            cboDefaultLanguage.SelectedValue = currentDefaultLang;
        }
    }
      
    /// <summary>
    /// Saves or adds the application.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnSave_Click(object sender, EventArgs e) {
        Page.Validate("vldLanguages");
        if(Page.IsValid) {
            try {
                bool editing = false;
                string applicationId = null;
                try {
                    bool.TryParse((Session["editing"] ?? bool.FalseString).ToString(), out editing);
                    applicationId = (Session["appid"] ?? string.Empty).ToString();
                } catch {
                    throw new ResourceBlenderException(I18nUtils.GetString("Errors", "SessionExpired"));
                }
                RBApplication application = new RBApplication() {
                    ApplicationName = txtAppName.Text.Trim(),
                    DisplayName = txtDisplayName.Text.Trim(),
                    DefaultLanguage = cboDefaultLanguage.SelectedValue
                };
                List<string> selectedLangs = new List<string>();
                foreach(ListItem itm in lstSelectedLangs.Items) {
                    selectedLangs.Add(itm.Value);
                }
                application.Languages = selectedLangs;

                if(application.ApplicationName.Length > 255) { // app name too long
                    throw new ResourceBlenderException(I18nUtils.GetString("Errors", "NameTooLongFmt", "255"));
                } else if(application.DisplayName.Length > 255) { // displayname too long
                    throw new ResourceBlenderException(I18nUtils.GetString("Errors", "NameTooLongFmt", "255"));
                } else if(string.IsNullOrEmpty(application.DefaultLanguage) || application.DefaultLanguage.Length > 7) { // default language wrong length
                    throw new ResourceBlenderException(I18nUtils.GetString("Errors", "StringWrongLengthFmt", I18nUtils.GetString("UIStrings", "DefaultLanguage"), "1", "7"));
                }
                if(editing) {
                    application.ID = applicationId;
                    ResourceBlenderDAL.EditApplication(application);
                } else {
                    ResourceBlenderDAL.AddApplication(application);
                }
                mltMain.ActiveViewIndex = 0;
                BindApplicationsGrid();
                Session["editing"] = bool.FalseString;
            } catch(Exception ex) {
                lblErrorDescription.Text = ex.Message;
                mltMain.ActiveViewIndex = 3;
            }
        }
    }
    #endregion

    #region Deleting
    /// <summary>
    /// Confirms deletion of a application and removes it from the database.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnOk_Click(object sender, EventArgs e) {
        try {
            string applicationId = null;
            try {
                applicationId = Session["appid"].ToString();
            } catch {
                throw new ResourceBlenderException(I18nUtils.GetString("Errors", "SessionExpired"));
            }
            ResourceBlenderDAL.DeleteApplication(new RBApplication() { ID = applicationId });
            BindApplicationsGrid();
            mltMain.ActiveViewIndex = 0;
        } catch(Exception ex) {
            lblErrorDescription.Text = ex.Message;
            mltMain.ActiveViewIndex = 3;
        }
    }
    
    /// <summary>
    /// Redirects the user to the 'Manage applications' page.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnCancelDelete_Click(object sender, EventArgs e) {
        mltMain.ActiveViewIndex = 0;
    }
    #endregion

}
